import React, { useState, useRef, useEffect, useCallback } from 'react'
import './VirtualList.css'

/**
 * 虚拟列表组件
 * 用于高效渲染大型列表数据
 * 
 * @param {Object} props 组件属性
 * @param {Array} props.items 列表数据数组
 * @param {Function} props.renderItem 渲染单个列表项的函数
 * @param {number} props.itemHeight 列表项的固定高度（像素）
 * @param {number} props.overScanCount 预渲染的额外项数（前后各渲染的项数）
 * @param {string} props.className 自定义CSS类名
 * @param {Object} props.style 自定义样式
 */
const VirtualList = ({ 
  items = [], 
  renderItem, 
  itemHeight = 50, 
  overScanCount = 5, 
  className = '', 
  style = {} 
}) => {
  const [visibleRange, setVisibleRange] = useState({ start: 0, end: 0 })
  const containerRef = useRef(null)
  const wrapperRef = useRef(null)
  
  // 计算可见范围的索引
  const calculateVisibleRange = useCallback(() => {
    const container = containerRef.current
    if (!container) return
    
    const { scrollTop, clientHeight } = container
    
    // 计算可见项的起始索引
    const start = Math.max(0, Math.floor(scrollTop / itemHeight) - overScanCount)
    
    // 计算可见项的结束索引
    const end = Math.min(
      items.length - 1,
      Math.ceil((scrollTop + clientHeight) / itemHeight) + overScanCount
    )
    
    setVisibleRange({ start, end })
  }, [items.length, itemHeight, overScanCount])
  
  // 监听滚动事件
  useEffect(() => {
    const container = containerRef.current
    if (!container) return
    
    // 初始计算可见范围
    calculateVisibleRange()
    
    // 添加滚动事件监听器
    container.addEventListener('scroll', calculateVisibleRange, { passive: true })
    
    // 监听窗口大小变化，处理容器大小改变的情况
    const handleResize = () => calculateVisibleRange()
    window.addEventListener('resize', handleResize)
    
    // 清理函数
    return () => {
      container.removeEventListener('scroll', calculateVisibleRange)
      window.removeEventListener('resize', handleResize)
    }
  }, [calculateVisibleRange])
  
  // 当items数组改变时重新计算可见范围
  useEffect(() => {
    calculateVisibleRange()
  }, [items.length, calculateVisibleRange])
  
  // 获取可见的列表项
  const visibleItems = items.slice(visibleRange.start, visibleRange.end + 1)
  
  // 计算偏移量
  const offsetY = visibleRange.start * itemHeight
  
  // 计算滚动容器的总高度
  const totalHeight = items.length * itemHeight
  
  return (
    <div 
      ref={containerRef}
      className={`virtual-list-container ${className}`}
      style={{ overflow: 'auto', ...style }}
    >
      <div 
        ref={wrapperRef}
        className="virtual-list-wrapper"
        style={{ height: `${totalHeight}px`, position: 'relative' }}
      >
        <div 
          className="virtual-list-items"
          style={{ 
            transform: `translateY(${offsetY}px)`,
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0
          }}
        >
          {visibleItems.map((item, index) => {
            const itemIndex = visibleRange.start + index
            return (
              <div 
                key={itemIndex} 
                className="virtual-list-item"
                style={{ height: `${itemHeight}px`, boxSizing: 'border-box' }}
              >
                {renderItem(item, itemIndex)}
              </div>
            )
          })}
        </div>
      </div>
    </div>
  )
}

export default VirtualList